using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using Gj;
using SimpleJSON;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Callbacks;
#if UNITY_IOS
using UnityEditor.iOS.Xcode;
#endif
using UnityEditor.XCodeEditor;
#endif
using UnityEngine;
using UnityEngine.TestTools;

public class PostProcessor: IPreprocessBuildWithReport
{
    public int callbackOrder { get { return 99; } }
    // Build postprocessor. Currently only needed on:
    // - iOS: no dynamic libraries, so plugin source files have to be copied into Xcode project
    [PostProcessBuild(99)]
    public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
    {
    Debug.LogError("OnPostProcessBuild"+target+":"+pathToBuiltProject);
        switch (target)
        {
            case BuildTarget.iOS:
                OnPostprocessBuildIOS(pathToBuiltProject);
                break;
            case BuildTarget.Android:
                OnPostprocessBuildAndroid(pathToBuiltProject);
                break;
            case BuildTarget.StandaloneOSX:
                OnPostprocessBuildStandaloneOSX(pathToBuiltProject);
                break;
            case BuildTarget.StandaloneWindows64:
                OnPostprocessBuildStandaloneWindows(pathToBuiltProject);
                break;
            default:
                break;
        }
    }
        public void OnPreprocessBuild(BuildTarget target, string pathToBuiltProject)
        {
    Debug.LogError("OnPreprocessBuild"+target+":"+pathToBuiltProject);
            switch (target)
            {
                case BuildTarget.StandaloneOSX:
                    OnPreprocessBuildStandaloneOSX(pathToBuiltProject);
                    break;
                case BuildTarget.StandaloneWindows64:
                    OnPreprocessBuildStandaloneWindows(pathToBuiltProject);
                    break;
                default:
                    break;
            }
        }

        public void OnPreprocessBuild(BuildReport report)
        {
    Debug.LogError("OnPreprocessBuild"+report.summary.platform+":"+report.summary.outputPath);
            switch (report.summary.platform)
            {
                case BuildTarget.StandaloneOSX:
                    OnPreprocessBuildStandaloneOSX(report.summary.outputPath);
                    break;
                case BuildTarget.StandaloneWindows64:
                    OnPreprocessBuildStandaloneWindows(report.summary.outputPath);
                    break;
                default:
                    break;
            }
        }
    // Replaces the first C++ macro with the given name in the source file. Only changes
    // single-line macro declarations, if multi-line macro declaration is detected, the
    // function returns without changing it. Macro name must be a valid C++ identifier.
    internal static void ReplaceMacro(ref string[] lines, string name, string newValue)
    {
        var flag = false;

        for (int i = 0; i < lines.Count(); i++)
        {
            if (lines[i].Contains(newValue))
            {
                flag = true;
            }
        }

        if (flag) return;
        for (int i = 0; i < lines.Count(); i++)
        {
            lines[i] = lines[i].Replace(name, newValue);
        }
    }

    static void UpdateDefinesInFile(string file, Dictionary<string, string> valuesToUpdate)
    {
        string[] src = File.ReadAllLines(file);
        var copy = (string[])src.Clone();

        foreach (var kvp in valuesToUpdate)
            ReplaceMacro(ref copy, kvp.Key, kvp.Value);

        if (!copy.SequenceEqual(src))
            File.WriteAllLines(file, copy);
    }
    internal static void ReplaceMacro(ref string[] lines, string name, string findValue, string newValue)
    {
        var flag = false;

        for (int i = 0; i < lines.Count(); i++)
        {
            if (lines[i].Contains(findValue))
            {
                flag = true;
            }
        }

        if (flag) return;
        for (int i = 0; i < lines.Count(); i++)
        {
            lines[i] = lines[i].Replace(name, newValue);
        }
    }
    static void AppendDefinesInFile(string file, Dictionary<string, string[]> valuesToUpdate)
    {
        string[] src = File.ReadAllLines(file);
        var copy = (string[])src.Clone();

        foreach (var kvp in valuesToUpdate)
        {
            ReplaceMacro(ref copy, kvp.Key, kvp.Value[0], kvp.Value[1]);
        }


        if (!copy.SequenceEqual(src))
            File.WriteAllLines(file, copy);
    }

#if UNITY_IOS
  //添加lib方法
  static void AddLibToProject(PBXProject inst, string targetGuid, string lib)
  {
    string fileGuid = inst.AddFile("usr/lib/" + lib, "Frameworks/" + lib, PBXSourceTree.Sdk);
    inst.AddFileToBuild(targetGuid, fileGuid);
  }
#endif

    private static void OnPreprocessBuildStandaloneWindows(string pathToBuiltProject)
    {
        OnPreprocessChannelStandalone(pathToBuiltProject);
    }
    private static void OnPostprocessBuildStandaloneWindows(string pathToBuiltProject)
    {
        OnPostprocessChannelStandalone(pathToBuiltProject);
    }

    private static void OnPreprocessBuildStandaloneOSX(string pathToBuiltProject)
    {
        string taptaplogin = Path.Combine(System.Environment.CurrentDirectory, "Library/PackageCache/com.taptap.tds.login@3.29.4/Plugins/iOS/Resource");
        Debug.Log("remove path:"+taptaplogin);
        FileTools.MoveFile(taptaplogin, Path.Combine(System.Environment.CurrentDirectory, "macTmp"));
        OnPreprocessChannelStandalone(pathToBuiltProject);
    }
    private static void OnPostprocessBuildStandaloneOSX(string pathToBuiltProject)
    {
        string taptaplogin = Path.Combine(pathToBuiltProject, "Contents/PlugIns/TapLoginResource.bundle");
        Debug.Log("remove path:"+taptaplogin);
        if (File.Exists(taptaplogin))
        {
            Debug.Log("remove path success:"+taptaplogin);
            File.Delete(taptaplogin);
        }

        OnPostprocessChannelStandalone(pathToBuiltProject);
    }

    
    private static void OnPreprocessChannelStandalone(string pathToBuiltProject)
    {
        ChannelSettings loadedSettings = (ChannelSettings)Resources.Load("ChannelSettings", typeof(ChannelSettings));

        if (loadedSettings != null)
        {
            var lower = pathToBuiltProject.ToLowerInvariant();
            foreach (var channel in loadedSettings.channels)
            {
                if (lower.Contains(channel.id.ToLowerInvariant()))
                {
                    Debug.Log("channel: match->" + channel.channel + " : " + channel.id);
                    loadedSettings.Default = new ChannelIdentity()
                    {
                        channel = channel.channel,
                        id = channel.id,
                    };
                    break;
                }
            }

            EditorUtility.SetDirty(loadedSettings);
            // string configPath = "Assets/Resources/ChannelSettings.asset";
            // File.WriteAllText(configPath, newConfigJson);
            AssetDatabase.Refresh();
        }
    }
    private static void OnPostprocessChannelStandalone(string pathToBuiltProject)
    {
        
    }
    private static void OnPostprocessBuildIOS(string pathToBuiltProject)
    {
        // We use UnityEditor.iOS.Xcode API which only exists in iOS editor module
#if UNITY_IOS
    // 替换pod
    string podPath = pathToBuiltProject + "/Podfile";
    XClass podfile = new XClass(podPath);
    if (podfile.ContainText("https://github.com/CocoaPods/Specs.git"))
    {
      podfile.Replace("https://github.com/CocoaPods/Specs.git",
        "https://github.com/CocoaPods/Specs");
    }
    if (podfile.ContainText("https://github.com/CocoaPods/Specs"))
    {
      podfile.Replace("https://github.com/CocoaPods/Specs",
        "https://gitee.com/mirrors/CocoaPods-Specs");
    }
    string projPath = pathToBuiltProject + "/Unity-iPhone.xcodeproj/project.pbxproj";

    UnityEditor.iOS.Xcode.PBXProject proj = new UnityEditor.iOS.Xcode.PBXProject();
    proj.ReadFromString(File.ReadAllText(projPath));
    string target = proj.GetUnityMainTargetGuid();
    string frameworkTarget = proj.GetUnityFrameworkTargetGuid();

    proj.AddBuildProperty(target, "OTHER_LDFLAGS", "-ObjC -fobjc-arc");

    // fake unity connect
    var token = proj.GetBuildPropertyForAnyConfig(frameworkTarget, "USYM_UPLOAD_AUTH_TOKEN");
    if (string.IsNullOrEmpty(token))
    {
      token = "FakeToken";
    }
    proj.SetBuildProperty(frameworkTarget, "USYM_UPLOAD_AUTH_TOKEN", token);
    
    token = proj.GetBuildPropertyForAnyConfig(target, "USYM_UPLOAD_AUTH_TOKEN");
    if (string.IsNullOrEmpty(token))
    {
      token = "FakeToken";
    }
    proj.SetBuildProperty(target, "USYM_UPLOAD_AUTH_TOKEN", token);

    // 添加framwrok
    proj.AddFrameworkToProject(target, "ARKit.framework", false);
    proj.AddFrameworkToProject(target, "Security.framework", false);
    proj.AddFrameworkToProject(target, "CoreTelephony.framework", false);
    proj.AddFrameworkToProject(target, "SystemConfiguration.framework", false);
    proj.AddFrameworkToProject(target, "CoreGraphics.framework", false);
    proj.AddFrameworkToProject(target, "ImageIO.framework", false);
    proj.AddFrameworkToProject(target, "CoreData.framework", false);
    proj.AddFrameworkToProject(target, "GameKit.framework", false);

    //添加lib
    AddLibToProject(proj, target, "libsqlite3.tbd");
    AddLibToProject(proj, target, "libc++.tbd");
    AddLibToProject(proj, target, "libz.tbd");
    AddLibToProject(proj, target, "libstdc++.tbd");
    AddLibToProject(proj, target, "libiconv.tbd");

    File.WriteAllText(projPath, proj.WriteToString());

    Directory.CreateDirectory(Path.Combine(pathToBuiltProject, "Libraries/Unity"));

    string plistPath = Path.Combine(pathToBuiltProject, "Info.plist");

    PlistDocument plist = new PlistDocument();
    plist.ReadFromString(File.ReadAllText(plistPath));

    string plistReleasePath = Path.Combine(pathToBuiltProject, "Unity-iPhone/"+Application.productName.Split(' ')[0].ToLower()+"Release.entitlements");
    PlistDocument plistRelease = new PlistDocument();
    if (File.Exists(plistReleasePath))
    {
      plistRelease.ReadFromString(File.ReadAllText(plistReleasePath));
    }

    PlistElement pel;

    // 添加Capabilities
    PlistElementArray capabilities;
    if (plist.root.values.TryGetValue("UIRequiredDeviceCapabilities", out pel))
    {
      capabilities = pel.AsArray();
    }
    else
    {
      capabilities = plist.root.CreateArray("UIRequiredDeviceCapabilities");
    }
    var capabilityList = new string[capabilities.values.Count];
    {
      var capabilitieE = capabilities.values.GetEnumerator();
      var i = 0;
      while (capabilitieE.MoveNext())
      {
        capabilityList[i] = capabilitieE.Current.AsString();
        i++;
      }
    }
    PlistElementArray domainsRelease;
    if (plistRelease.root.values.TryGetValue("com.apple.developer.associated-domains", out pel))
    {
      domainsRelease = pel.AsArray();
    }
    else
    {
      domainsRelease = plistRelease.root.CreateArray("com.apple.developer.associated-domains");
    }
    var domainList = new string[domainsRelease.values.Count];
    {
      var domainE = domainsRelease.values.GetEnumerator();
      var i = 0;
      while (domainE.MoveNext())
      {
        domainList[i] = domainE.Current.AsString();
        i++;
      }
    }
    
    if (!domainList.Contains("webcredentials:example.com")) domainsRelease.AddString("webcredentials:example.com");

    var appName = AppNameManager.settings;
    if (appName.targets.Count > 0)
    {
      string projPathTmp = pathToBuiltProject + "/Unity-iPhone.xcodeproj/project.pbxproj";
      var projTmp = new ksthip.UnityEditor.iOS.Xcode.PBXProject();
      projTmp.ReadFromFile(projPathTmp);
      if (plist.root.values.ContainsKey("CFBundleDisplayName"))
      {
        plist.root.values.Remove("CFBundleDisplayName");
      }

      if (plist.root.values.ContainsKey("LSHasLocalizedDisplayName"))
      {
        plist.root.values.Remove("LSHasLocalizedDisplayName");
      }
      plist.root.values.Add("LSHasLocalizedDisplayName", new PlistElementBoolean(true));

      
      var e = appName.targets.GetEnumerator();
      while (e.MoveNext())
      {
        string folder = pathToBuiltProject + "/" +PBXProject.GetUnityTestTargetName()+"/"+ AppNameManager.GetIos(e.Current.language) + ".lproj";
        if (!Directory.Exists(folder))
        {
          Directory.CreateDirectory(folder);
        }
        string filePath = folder + "/InfoPlist.strings";
        string content = "\"CFBundleDisplayName\" = \"" + e.Current.name + "\";\n";
        content += "\"CFBundleName\" = \"" + e.Current.name + "\";\n";
        File.WriteAllText(filePath, content);
        projTmp.AddLocalization("InfoPlist.strings", AppNameManager.GetIos(e.Current.language), filePath);
      }
      e.Dispose();
      projTmp.WriteToFile(projPathTmp);
    }
    
    // 添加社交信息
    var settings = SocialManager.settings;
    if (settings.GameCenter)
    {
      if (!capabilityList.Contains("gamekit")) capabilities.AddString("gamekit");
    }

    // CFBundleURLTypes
    PlistElementArray urlTypes;
    if (plist.root.values.TryGetValue("CFBundleURLTypes", out pel))
    {
      urlTypes = pel.AsArray();
    }
    else
    {
      urlTypes = plist.root.CreateArray("CFBundleURLTypes");
    }

    // LSApplicationQueriesSchemes
    PlistElementArray schemes;
    if (plist.root.values.TryGetValue("LSApplicationQueriesSchemes", out pel))
    {
      schemes = pel.AsArray();
    }
    else
    {
      schemes = plist.root.CreateArray("LSApplicationQueriesSchemes");
    }

    var schemeList = new string[schemes.values.Count];
    {
      var schemesE = schemes.values.GetEnumerator();
      var i = 0;
      while (schemesE.MoveNext())
      {
        schemeList[i] = schemesE.Current.AsString();
        i++;
      }
    }

    // 微信
    if (!String.IsNullOrEmpty(settings.WechatAppKey))
    {
      //插入dict
      var urlDict = urlTypes.AddDict();
      urlDict.SetString("CFBundleTypeRole", "Editor");
      urlDict.SetString("CFBundleURLName", "wechat");
      //插入array
      var urlInnerArray = urlDict.CreateArray("CFBundleURLSchemes");
      urlInnerArray.AddString(settings.WechatAppKey);

      if (!schemeList.Contains("weixin")) schemes.AddString("weixin");
      if (!schemeList.Contains("wechat")) schemes.AddString("wechat");
      if (!schemeList.Contains("weixinULAPI")) schemes.AddString("weixinULAPI");

      plist.root.SetString("WechatLink", settings.WechatLink);
      Uri weixinUri = new Uri(settings.WechatLink);
      var wechatDomain = weixinUri.Host;
      if (!domainList.Contains("applinks:"+wechatDomain)) domainsRelease.AddString("applinks:"+wechatDomain);
    }

    if (!String.IsNullOrEmpty(settings.QQAppKey))
    {
      //插入dict
      var urlDict = urlTypes.AddDict();
      urlDict.SetString("CFBundleTypeRole", "Editor");
      urlDict.SetString("CFBundleURLName", "qq");
      //插入array
      var urlInnerArray = urlDict.CreateArray("CFBundleURLSchemes");
      urlInnerArray.AddString("tencent" + settings.QQAppKey);
    }

    if (!String.IsNullOrEmpty(settings.TapTap))
    {
      var taptap
      //插入dict
      var urlDict = urlTypes.AddDict();
      urlDict.SetString("CFBundleTypeRole", "Editor");
      urlDict.SetString("CFBundleURLName", "qq");
      //插入array
      var urlInnerArray = urlDict.CreateArray("CFBundleURLSchemes");
      urlInnerArray.AddString("taptap" + settings.QQAppKey);
    }

    if (!String.IsNullOrEmpty(settings.FacebookAppKey))
    {
      //插入dict
      var urlDict = urlTypes.AddDict();
      urlDict.SetString("CFBundleTypeRole", "Editor");
      urlDict.SetString("CFBundleURLName", "facebook");
      //插入array
      var urlInnerArray = urlDict.CreateArray("CFBundleURLSchemes");
      urlInnerArray.AddString("fb" + settings.FacebookAppKey);
      if (!schemeList.Contains("fbapi"))schemes.AddString("fbapi");
      if (!schemeList.Contains("fb-messenger-share-api"))schemes.AddString("fb-messenger-share-api");
      if (!schemeList.Contains("fbauth2"))schemes.AddString("fbauth2");
      if (!schemeList.Contains("fbshareextension"))schemes.AddString("fbshareextension");
      if (!schemeList.Contains("fb"))schemes.AddString("fb");

      // facebook特殊
      plist.root.SetString("FacebookAppID", settings.FacebookAppKey);
      plist.root.SetString("FacebookDisplayName", settings.FacebookDisplayName);
    }

    File.WriteAllText(plistPath, plist.WriteToString());
    File.WriteAllText(plistReleasePath, plistRelease.WriteToString());

    //插入代码
    //读取UnityAppController.mm文件
    string unityAppControllerPath = pathToBuiltProject + "/Classes/UnityAppController.mm";
    XClass UnityAppController = new XClass(unityAppControllerPath);

    if (!UnityAppController.ContainText("#import <Libraries/Gj-sparrow/Plugins/iOS/social.h>"))
    {
      //在指定代码后面增加一行代码
      UnityAppController.WriteBelow("#include \"PluginBase/AppDelegateListener.h\"", "#import <Libraries/Gj-sparrow/Plugins/iOS/social.h>");

      string urlCode = "\n" +
                       "  BOOL result = [[SocialManager defaultManager] handleOpenURL:url options:options];\n" +
                       "  if(result) return result;\n";
      //在指定代码后面增加一大行代码
      UnityAppController.WriteBelow("- (BOOL)application:(UIApplication*)app openURL:(NSURL*)url options:(NSDictionary<NSString*, id>*)options\n{", urlCode);

      string registerCode = "\n";
      // if (!String.IsNullOrEmpty(settings.WechatAppKey))
      // {
      //   registerCode += "    [[SocialManager defaultManager] setPlatform:SocialPlatformType_Wechat appKey:[NSString stringWithUTF8String:\"" + settings.WechatAppKey + "\"] appSecret:[NSString stringWithUTF8String:\"\"] redirectURL:nil];\n";
      // }
      // if (!String.IsNullOrEmpty(settings.QQAppKey))
      // {
      //   registerCode += "    [[SocialManager defaultManager] setPlatform:SocialPlatformType_QQ appKey:[NSString stringWithUTF8String:\"" + settings.QQAppKey + "\"] appSecret:[NSString stringWithUTF8String:\"\"] redirectURL:nil];\n";
      // }
      // if (!String.IsNullOrEmpty(settings.FacebookAppKey))
      // {
      //   registerCode += "    [[SocialManager defaultManager] setPlatform:SocialPlatformType_Facebook appKey:[NSString stringWithUTF8String:\"" + settings.FacebookAppKey + "\"] appSecret:[NSString stringWithUTF8String:\"\"] redirectURL:nil];\n";
      // }
      registerCode += "\n    [[SocialManager defaultManager] launch:launchOptions];\n";
      UnityAppController.WriteBelow("// if you wont use keyboard you may comment it out at save some memory", registerCode);
    }

#endif // #if UNITY_IOS
    }
    private static void OnPostprocessBuildAndroid(string pathToBuiltProject)
    {
        // 添加Androidx
        var gradle = pathToBuiltProject + "/gradle.properties";
        if (!ContainText(gradle, "useAndroidX"))
        {
            WriteBelow(gradle, "\n", "android.useAndroidX=true\nandroid.enableJetifier=true\n");
        }

        if (!ContainText(gradle, "unityStreamingAssets"))
        {
            WriteBelow(gradle, "\n", "unityStreamingAssets=.unity3d\n");
        }

        // if (!ContainText(gradle, "enableR8"))
        // {
        //     WriteBelow(gradle, "\n", "android.enableR8=false\n");
        // }



        string launcherPath = pathToBuiltProject + "/launcher";
        string unityPath = pathToBuiltProject + "/unityLibrary";

        // 读取gradle
        string launcherGradle = launcherPath + "/build.gradle";
        if (File.Exists(launcherGradle + ".NEW"))
        {
            File.Delete(launcherGradle);
            File.Move(launcherGradle + ".NEW", launcherGradle);
        }
        string unityGradle = unityPath + "/build.gradle";
        if (File.Exists(unityGradle + ".NEW"))
        {
            File.Delete(unityGradle);
            File.Move(unityGradle + ".NEW", unityGradle);
        }
        // 读取xml
        string launcherXmlPath = launcherPath + "/src/main/AndroidManifest.xml";
        if (File.Exists(launcherXmlPath + ".NEW"))
        {
            File.Delete(launcherXmlPath);
            File.Move(launcherXmlPath + ".NEW", launcherXmlPath);
        }
        XmlDocument launcherXmlDoc = new XmlDocument();
        launcherXmlDoc.Load(launcherXmlPath);

        string xmlPath = unityPath + "/src/main/AndroidManifest.xml";
        if (File.Exists(xmlPath + ".NEW"))
        {
            File.Delete(xmlPath);
            File.Move(xmlPath + ".NEW", xmlPath);
        }
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(xmlPath);
        XmlNamespaceManager ns = new XmlNamespaceManager(xmlDoc.NameTable);
        //        ns.AddNamespace("android", "a");
        ns.AddNamespace("android", "http://schemas.android.com/apk/res/android");
        ns.AddNamespace("tools", "http://schemas.android.com/tools");

        // 包名
        XmlNode launcherNode = launcherXmlDoc.SelectSingleNode("manifest");
        XmlNode launcherApplication = launcherNode?.SelectSingleNode("application");

        XmlNode node = xmlDoc.SelectSingleNode("manifest");
        XmlNode application = node?.SelectSingleNode("application");

        // 获取包名，兼容新旧版本 Android Gradle 插件
        string package = null;
        
        if (node != null && node.Attributes != null && node.Attributes["package"] != null)
        {
            package = node.Attributes["package"].Value;
        }

        string identity = Application.identifier;

        // 如果 AndroidManifest.xml 中没有 package 属性，使用 Unity 的应用标识符
        if (string.IsNullOrEmpty(package))
        {
            package = identity;
        }

        // 自动android下载更新设置
        var app = Resource.Settings;
        if (app.AppInfoPath != "" && application != null)
        {
            var oldFileProviderNode = FindNode(xmlDoc, "manifest/application/provider", "name", ns, "androidx.core.content.FileProvider");
            if (oldFileProviderNode != null) application.RemoveChild(oldFileProviderNode);

            var provider = xmlDoc.CreateElement("provider");

            provider.SetAttribute("name", ns.LookupNamespace("android"), "androidx.core.content.FileProvider");
            provider.SetAttribute("authorities", ns.LookupNamespace("android"), "${applicationId}.fileProvider");
            provider.SetAttribute("exported", ns.LookupNamespace("android"), "false");
            provider.SetAttribute("grantUriPermissions", ns.LookupNamespace("android"), "true");
            provider.SetAttribute("ignore", ns.LookupNamespace("tools"), "WrongManifestParent");
            var metaData = xmlDoc.CreateElement("meta-data");
            metaData.SetAttribute("name", ns.LookupNamespace("android"), "android.support.FILE_PROVIDER_PATHS");
            metaData.SetAttribute("resource", ns.LookupNamespace("android"), "@xml/filepaths");
            provider.AppendChild(metaData);
            application.AppendChild(provider);

            AddPermission(xmlDoc, ns, "android.permission.REQUEST_INSTALL_PACKAGES");

            // 写入filepaths文件
            string pathFileDir = unityPath + "/src/main/res/xml";
            if (!Directory.Exists(pathFileDir))
            {
                Directory.CreateDirectory(pathFileDir);
            }
            File.WriteAllText(pathFileDir + "/filepaths.xml", "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<paths>\n<root-path name=\"root\" path=\"\" />\n<external-path name=\"external_storage_root\" path=\".\" />\n<external-path name=\"external_storage_download\" path=\"Download\" />\n<external-path path=\"mimoDownload\" name=\"files_root\" />\n</paths>");
        }

        var appName = AppNameManager.settings;
        if (appName.targets.Count > 0)
        {
            string baseS = ReadAll(launcherPath + "/src/main/res/values/strings.xml");
            var e = appName.targets.GetEnumerator();
            while (e.MoveNext())
            {
                // 写入strings.xml文件
                string pathFileDir = launcherPath + "/src/main/res/values-" + AppNameManager.GetAndroid(e.Current.language);
                if (!Directory.Exists(pathFileDir))
                {
                    Directory.CreateDirectory(pathFileDir);
                }
                File.WriteAllText(pathFileDir + "/strings.xml", baseS.Replace(PlayerSettings.productName, e.Current.name.Replace("'", "\\'")));
            }
            e.Dispose();
        }

        var settings = SocialManager.settings;

        if (!String.IsNullOrEmpty(settings.WechatAppKey) && application != null)
        {
            var oldActivityNode = FindNode(xmlDoc, "manifest/application/activity", "name", ns, identity + ".wxapi.WXEntryActivity");
            if (oldActivityNode != null) application.RemoveChild(oldActivityNode);


            // UpdateDefinesInFile(
            //   unityPath + "/src/main/java/com/ueffort/social/platform/WechatProvider.java",
            //   new Dictionary<string, string>() { { "APP_ID", settings.WechatAppKey } }
            // );
            // 移动activity到对应包目录
            var source = unityPath + "/src/main/java/com/ueffort/social/wxapi/";
            var sourceProxy = unityPath + "/src/main/java/com/ueffort/social/wxapiProxy/WXEntryProxy.java";
            if (Directory.Exists(source))
            {
                if (ChannelManager.settings != null && ChannelManager.settings.channels.Count > 0)
                {
                    var e = ChannelManager.settings.channels.GetEnumerator();
                    while (e.MoveNext())
                    {
                        var info = e.Current;
                        if (info.target != BuildTarget.Android) continue;

                        var socialList = info.social.GetEnumerator();
                        while (socialList.MoveNext())
                        {
                            var platform = socialList.Current;
                            if (platform != SocialManager.Platform.Wechat)
                            {
                                continue;
                            }
                            var channelIdentity = (info.prefix.Length > 0 ? info.prefix + ".": "") + identity + (info.suffix.Length > 0 ? "." + info.suffix : "");
                            var dest = unityPath + "/src/main/social/wechat/java/" + channelIdentity.Replace('.', '/') + "/wxapi";
                            FileTools.MoveFile(source, dest, (p) =>
                            {
                                UpdateDefinesInFile(p, new Dictionary<string, string>() { { "com.ueffort.social.wxapi", channelIdentity + ".wxapi" }, { "APP_ID", settings.WechatAppKey } });
                            });
                            var destProxy = unityPath + "/src/main/java/" + identity.Replace('.', '/') + "/wxapi/WXEntryActivity.java";
                            FileTools.MoveFile(sourceProxy, destProxy, (p) =>
                            {
                                UpdateDefinesInFile(p, new Dictionary<string, string>() { { "com.ueffort.social.wxapiProxy", identity + ".wxapi" }, { "APP_ID", settings.WechatAppKey } });
                            });

                            var oldWechatNode = FindNode(xmlDoc, "manifest/application/activity", "name", ns, identity + ".${channelId}" + ".wxapi.WXEntryActivity");
                            if (oldWechatNode != null) application.RemoveChild(oldWechatNode);
                            // 添加 微信activity
                            XmlElement activity = xmlDoc.CreateElement("activity");

                            activity.SetAttribute("name", ns.LookupNamespace("android"), identity + "${wechatSocialDot}.wxapi.WXEntryActivity");
                            activity.SetAttribute("label", ns.LookupNamespace("android"), "${appName}");
                            activity.SetAttribute("theme", ns.LookupNamespace("android"), "@android:style/Theme.Translucent.NoTitleBar");
                            activity.SetAttribute("exported", ns.LookupNamespace("android"), "true");
                            activity.SetAttribute("taskAffinity", ns.LookupNamespace("android"), identity + "${wechatSocialDot}");
                            activity.SetAttribute("launchMode", ns.LookupNamespace("android"), "singleTask");

                            application.AppendChild(activity);
                        }
                        socialList.Dispose();
                    }
                    e.Dispose();
                }
                if (Directory.Exists(source))
                {
                    FileTools.DeleteFolder(source);
                }

                if (File.Exists(sourceProxy))
                {
                    File.Delete(sourceProxy);
                }
            }
            else
            {
                Debug.Log("miss " + source);
            }
        }

        if (!String.IsNullOrEmpty(settings.QQAppKey) && application != null)
        {
            var oldActivityNode = FindNode(xmlDoc, "manifest/application/activity", "name", ns, "com.tencent.tauth.AuthActivity");
            if (oldActivityNode != null) application.RemoveChild(oldActivityNode);
            var oldAssistActivityNode = FindNode(xmlDoc, "manifest/application/activity", "name", ns, "com.tencent.connect.common.AssistActivity");
            if (oldAssistActivityNode != null) application.RemoveChild(oldAssistActivityNode);

            var activity = xmlDoc.CreateElement("activity");

            activity.SetAttribute("name", ns.LookupNamespace("android"), "com.tencent.tauth.AuthActivity");
            activity.SetAttribute("noHistory", ns.LookupNamespace("android"), "true");
            activity.SetAttribute("launchMode", ns.LookupNamespace("android"), "singleTask");
            var interFilter = xmlDoc.CreateElement("intent-filter");
            var action = xmlDoc.CreateElement("action");
            action.SetAttribute("name", ns.LookupNamespace("android"), "android.intent.action.VIEW");
            interFilter.AppendChild(action);
            var category = xmlDoc.CreateElement("category");
            category.SetAttribute("name", ns.LookupNamespace("android"), "android.intent.category.DEFAULT");
            interFilter.AppendChild(category);
            var category1 = xmlDoc.CreateElement("category");
            category1.SetAttribute("name", ns.LookupNamespace("android"), "android.intent.category.BROWSABLE");
            interFilter.AppendChild(category1);
            var data = xmlDoc.CreateElement("data");
            data.SetAttribute("scheme", ns.LookupNamespace("android"), "tencent" + settings.QQAppKey);
            interFilter.AppendChild(data);
            activity.AppendChild(interFilter);
            application.AppendChild(activity);

            var activity1 = xmlDoc.CreateElement("activity");

            activity1.SetAttribute("name", ns.LookupNamespace("android"), "com.tencent.connect.common.AssistActivity");
            activity1.SetAttribute("configChanges", ns.LookupNamespace("android"), "orientation|keyboardHidden");
            activity1.SetAttribute("screenOrientation", ns.LookupNamespace("android"), "behind");
            activity1.SetAttribute("theme", ns.LookupNamespace("android"), "@android:style/Theme.Translucent.NoTitleBar");
            application.AppendChild(activity1);

            AddPermission(xmlDoc, ns, "android.permission.ACCESS_NETWORK_STATE");

            UpdateDefinesInFile(
              unityPath + "/src/main/java/com/ueffort/social/platform/QQProvider.java",
              new Dictionary<string, string>() { { "APP_ID", settings.QQAppKey }, { "APP_SOURCE", settings.QQDisplayName } }
            );
        }

        if (!String.IsNullOrEmpty(settings.FacebookAppKey) && application != null)
        {
            var oldIdNode = FindNode(xmlDoc, "manifest/application/meta-data", "name", ns, "com.facebook.sdk.ApplicationId");
            if (oldIdNode != null) application.RemoveChild(oldIdNode);
            var oldActivityNode = FindNode(xmlDoc, "manifest/application/activity", "name", ns, "com.facebook.FacebookActivity");
            if (oldActivityNode != null) application.RemoveChild(oldActivityNode);
            var oldTabActivityNode = FindNode(xmlDoc, "manifest/application/activity", "name", ns, "com.facebook.CustomTabActivity");
            if (oldTabActivityNode != null) application.RemoveChild(oldTabActivityNode);


            var metaData = xmlDoc.CreateElement("meta-data");
            metaData.SetAttribute("name", ns.LookupNamespace("android"), "com.facebook.sdk.ApplicationId");
            metaData.SetAttribute("value", ns.LookupNamespace("android"), "fb" + settings.FacebookAppKey);
            application.AppendChild(metaData);
            // 添加 facebook activity
            var activity = xmlDoc.CreateElement("activity");

            activity.SetAttribute("name", ns.LookupNamespace("android"), "com.facebook.FacebookActivity");
            activity.SetAttribute("configChanges", ns.LookupNamespace("android"), "keyboard|keyboardHidden|screenLayout|screenSize|orientation");
            activity.SetAttribute("label", ns.LookupNamespace("android"), "${appName}");
            application.AppendChild(activity);

            var activity1 = xmlDoc.CreateElement("activity");

            activity1.SetAttribute("name", ns.LookupNamespace("android"), "com.facebook.CustomTabActivity");
            activity1.SetAttribute("exported", ns.LookupNamespace("android"), "true");
            var interFilter = xmlDoc.CreateElement("intent-filter");
            var action = xmlDoc.CreateElement("action");
            action.SetAttribute("name", ns.LookupNamespace("android"), "android.intent.action.VIEW");
            interFilter.AppendChild(action);
            var category = xmlDoc.CreateElement("category");
            category.SetAttribute("name", ns.LookupNamespace("android"), "android.intent.category.DEFAULT");
            interFilter.AppendChild(category);
            var category1 = xmlDoc.CreateElement("category");
            category1.SetAttribute("name", ns.LookupNamespace("android"), "android.intent.category.BROWSABLE");
            interFilter.AppendChild(category1);
            var data = xmlDoc.CreateElement("data");
            data.SetAttribute("scheme", ns.LookupNamespace("android"), "fb" + settings.FacebookAppKey);
            interFilter.AppendChild(data);
            activity1.AppendChild(interFilter);
            application.AppendChild(activity1);


            // var provider = xmlDoc.CreateElement("provider");
            //
            // provider.SetAttribute("name", ns.LookupNamespace("android"), "com.facebook.ads.AudienceNetworkContentProvider");
            // provider.SetAttribute("authorities", ns.LookupNamespace("android"), "${applicationId}.AudienceNetworkContentProvider");
            // provider.SetAttribute("exported", ns.LookupNamespace("android"), "false");
            //   
            //   
            //   
            // application.AppendChild(provider);
        }

        if (!String.IsNullOrEmpty(settings.GoogleAppId) && application != null)
        {
            var oldIdNode = FindNode(xmlDoc, "manifest/application/meta-data", "name", ns, "com.google.android.gms.games.APP_ID");
            if (oldIdNode != null) application.RemoveChild(oldIdNode);
            var oldVersionNode = FindNode(xmlDoc, "manifest/application/meta-data", "name", ns, "com.google.android.gms.version");
            if (oldVersionNode != null) application.RemoveChild(oldVersionNode);
            
            var metaData = xmlDoc.CreateElement("meta-data");
            metaData.SetAttribute("name", ns.LookupNamespace("android"), "com.google.android.gms.games.APP_ID");
            metaData.SetAttribute("value", ns.LookupNamespace("android"), "@string/google_app_id");
            application.AppendChild(metaData);
            /*var versionMetaData = xmlDoc.CreateElement("meta-data");
            versionMetaData.SetAttribute("name", ns.LookupNamespace("android"), "com.google.android.gms.version");
            versionMetaData.SetAttribute("value", ns.LookupNamespace("android"), "@integer/google_play_services_version");
            application.AppendChild(versionMetaData);*/

            // 写入strings.xml文件
            string pathFileDir = unityPath + "/src/main/res/values";
            if (!Directory.Exists(pathFileDir))
            {
              Directory.CreateDirectory(pathFileDir);
            }
            File.WriteAllText(pathFileDir + "/strings.xml", "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n<string name=\"google_app_id\">"+settings.GoogleAppId+"</string>\n</resources>");

            AddPermission(xmlDoc, ns, "android.permission.READ_PHONE_STATE");
            UpdateDefinesInFile(
              unityPath + "/src/main/res/values/strings.xml",
              new Dictionary<string, string>() { { "GoogleAppId", settings.GoogleAppId } }
            );
        }

        if (!String.IsNullOrEmpty(settings.MiAppId) && application != null)
        {
            var oldFileProviderNode = FindNode(xmlDoc, "manifest/application/provider", "name", ns, "com.xiaomi.gamecenter.sdk.utils.MiFileProvider");
            if (oldFileProviderNode != null) application.RemoveChild(oldFileProviderNode);

            var provider = xmlDoc.CreateElement("provider");

            provider.SetAttribute("name", ns.LookupNamespace("android"), "com.xiaomi.gamecenter.sdk.utils.MiFileProvider");
            provider.SetAttribute("authorities", ns.LookupNamespace("android"), "${applicationId}.mi_fileprovider");
            provider.SetAttribute("exported", ns.LookupNamespace("android"), "false");
            provider.SetAttribute("grantUriPermissions", ns.LookupNamespace("android"), "true");
            provider.SetAttribute("ignore", ns.LookupNamespace("tools"), "WrongManifestParent");
            var metaData = xmlDoc.CreateElement("meta-data");
            metaData.SetAttribute("name", ns.LookupNamespace("android"), "android.support.FILE_PROVIDER_PATHS");
            metaData.SetAttribute("resource", ns.LookupNamespace("android"), "@xml/mio_file_paths");
            provider.AppendChild(metaData);
            application.AppendChild(provider);
        }

        var channels = ChannelManager.settings;
        var channelFlavors = "";
        var sign = "";
        var channelDependencies = "";
        var channelSourceSets = "";
        if (channels != null && channels.channels.Count > 0)
        {
            var oldChannelNode = FindNode(launcherXmlDoc, "manifest/application/meta-data", "name", ns, "channel");
            if (oldChannelNode != null) launcherApplication.RemoveChild(oldChannelNode);

            var oldChannelIdNode = FindNode(launcherXmlDoc, "manifest/application/meta-data", "name", ns, "channelId");
            if (oldChannelIdNode != null) launcherApplication.RemoveChild(oldChannelIdNode);

            channelFlavors = "productFlavors {\n";
            var e = channels.channels.GetEnumerator();
            var j = 0;
            while (e.MoveNext())
            {
                var info = e.Current;
                if (info.target != BuildTarget.Android) continue;
                var hasWechat = false;
                for (var i = 0; i < info.social.Count; i++)
                {
                    if (info.social[i] == SocialManager.Platform.Wechat) hasWechat = true;
                }
                channelFlavors += "\t\t" + info.channel + " {\n";
                channelFlavors += "\t\t\tdimension \"channel\"\n";
                channelFlavors += "\t\t\tapplicationId \"" + (info.prefix.Length > 0 ? info.prefix + ".": "") + identity + (info.suffix.Length > 0 ? "." + info.suffix : "") + "\"\n";
                channelFlavors += "\t\t\tmanifestPlaceholders = [\n" +
                                  "\t\t\t\tchannel: \"" + info.channel + "\",\n" +
                                  "\t\t\t\tchannelId: \"" + info.id + "\",\n" +
                                  "\t\t\t\tappName: \"" + (info.appName == "" ? "@string/app_name" : info.appName) + "\",\n" +
                                  "\t\t\t\tprivacyDialog: \"" + (info.needPrivacyDialog ? "Yes" : "No") + "\",\n" +
                                  "\t\t\t\twechatSocialDot: \"" + (hasWechat ? "." + info.id : "") + "\",\n" +
                                  "\t\t\t]\n";
                channelFlavors += "\t\t\tsigningConfig signingConfigs." + (info.suffix.Length > 0 ? info.suffix : "release") + "\n";
                channelFlavors += "\t\t}\n";
            }
            e.Dispose();
            channelFlavors += "\t}\n";

            channelDependencies += "\tdef currentFlavor = getCurrentFlavor()\n";
            channelDependencies += "\tdef includes = []\n";
            channelDependencies += "\tdef libraries = []\n";

            var dependencies = Path.Combine(Application.absoluteURL, "Assets/Gj-sparrow/Editor/ChannelDependencies.json");
            if (!File.Exists(dependencies))
            {
                Debug.LogErrorFormat("dependencies is miss:{0}", dependencies);
                return;
            }
            var dependenciesInfo = JSONNode.Parse(ReadAll(dependencies));
            var dependenciesObject = dependenciesInfo.AsObject;
            var baseList = dependenciesObject["base"].AsArray;
            var adList = dependenciesObject["ad"].AsArray;
            var socialList = dependenciesObject["social"].AsArray;
            var analyticsList = dependenciesObject["analytics"].AsArray;

            channelDependencies += GenerateType(unityPath, baseList, null);
            channelDependencies += GenerateType(unityPath, adList, "ad");
            channelDependencies += GenerateType(unityPath, socialList, "social");
            channelDependencies += GenerateType(unityPath, analyticsList, "analytics");

            e = channels.channels.GetEnumerator();
            j = 0;
            while (e.MoveNext())
            {
                var info = e.Current;
                if (info.target != BuildTarget.Android) continue;
                channelDependencies += "\t" + (j > 0 ? "else " : "") + "if (\"" + info.channel + "\".equalsIgnoreCase(currentFlavor)) {\n";
                for (var i = 0; i < info.ad.Count; i++)
                {
                    channelDependencies += "\t\tlibraries.addAll(ad" + AdManager.DefinePlatform[info.ad[i]] + "libraries)\n";
                    channelDependencies += "\t\tincludes.addAll(ad" + AdManager.DefinePlatform[info.ad[i]] + "includes)\n";
                }

                for (var i = 0; i < info.social.Count; i++)
                {
                    channelDependencies += "\t\tlibraries.addAll(social" + SocialManager.DefinePlatform[info.social[i]] + "libraries)\n";
                    channelDependencies += "\t\tincludes.addAll(social" + SocialManager.DefinePlatform[info.social[i]] + "includes)\n";
                }

                for (var i = 0; i < info.analytics.Count; i++)
                {
                    channelDependencies += "\t\tlibraries.addAll(analytics" + AnalyticsManager.DefinePlatform[info.analytics[i]] + "libraries)\n";
                    channelDependencies += "\t\tincludes.addAll(analytics" + AnalyticsManager.DefinePlatform[info.analytics[i]] + "includes)\n";
                }
                channelDependencies += "\t}\n";
                j++;
            }

            // if (j > 0)
            // {
            //   channelDependencies += "\telse{\n";
            //   
            //   
            //   
            //   var adE = adList.Children.GetEnumerator();
            //   while (adE.MoveNext())
            //   {
            //     var one = adE.Current.AsObject;
            //     var name = one["name"];
            //     channelDependencies += "\t\tlibraries.addAll(ad"+name+"libraries)\n";
            //     channelDependencies += "\t\tincludes.addAll(ad"+name+"includes)\n";
            //   }
            //   adE.Dispose();
            //   var socialE = socialList.Children.GetEnumerator();
            //   while (socialE.MoveNext())
            //   {
            //     var one = socialE.Current.AsObject;
            //     var name = one["name"];
            //     channelDependencies += "\t\tlibraries.addAll(social"+name+"libraries)\n";
            //     channelDependencies += "\t\tincludes.addAll(social"+name+"includes)\n";
            //   }
            //   socialE.Dispose();
            //   channelDependencies += "\t}\n";
            // }
            e.Dispose();
            channelDependencies += "\tfor(def j in includes) {\n" +
                                   "\t\tif (j.contains(\"aar\")){\n" +
                                   "\t\t\tj = j.replace(\".aar\",\"\")\n" +
                                   "\t\t\timplementation (name: j, ext: 'aar')\n" +
                                   "\t\t}else{\n" +
                                   "\t\t\timplementation files(\"libs/\"+j)\n" +
                                   "\t\t}\n" +
                                   "\t}\n";
            channelDependencies += "\tfor(def j in libraries) {\n" +
                                   "\t\timplementation j , {\n" +
                                   "\t\t\texclude group: 'com.google.protobuf', module: 'protobuf-java'\n" +
                                   "\t\t}\n" +
                                   "\t}\n";

            // 转移文件
            // GenerateSource(baseList, "base", unityPath);
            GenerateSource(adList, "ad", unityPath);
            GenerateSource(socialList, "social", unityPath);

            channelSourceSets += "\tsourceSets {\n";
            channelSourceSets += "\t\tmain {\n";
            channelSourceSets += "\t\t\tdef currentFlavor = getCurrentFlavor()\n";
            e = channels.channels.GetEnumerator();
            j = 0;
            string p = "";
            while (e.MoveNext())
            {
                var info = e.Current;
                if (info.target != BuildTarget.Android) continue;
                channelSourceSets += "\t\t\t" + (j > 0 ? "else " : "") + "if (\"" + info.channel + "\".equalsIgnoreCase(currentFlavor)) {\n";
                for (var i = 0; i < info.ad.Count; i++)
                {
                    p = "src/main/ad/" + AdManager.DefinePlatform[info.ad[i]] + "/java";
                    if (Directory.Exists(unityPath + "/" + p)) channelSourceSets += "\t\t\t\tjava.srcDirs \"" + p + "\"\n";
                    p = "src/main/ad/" + AdManager.DefinePlatform[info.ad[i]] + "/jniLibs";
                    if (Directory.Exists(unityPath + "/" + p)) channelSourceSets += "\t\t\t\tjniLibs.srcDirs \"" + p + "\"\n";
                    p = "src/main/ad/" + AdManager.DefinePlatform[info.ad[i]] + "/res";
                    if (Directory.Exists(unityPath + "/" + p)) channelSourceSets += "\t\t\t\tres.srcDirs \"" + p + "\"\n";
                }

                for (var i = 0; i < info.social.Count; i++)
                {
                    p = "src/main/social/" + SocialManager.DefinePlatform[info.social[i]] + "/java";
                    if (Directory.Exists(unityPath + "/" + p)) channelSourceSets += "\t\t\t\tjava.srcDirs \"" + p + "\"\n";
                    p = "src/main/social/" + SocialManager.DefinePlatform[info.social[i]] + "/jniLibs";
                    if (Directory.Exists(unityPath + "/" + p)) channelSourceSets += "\t\t\t\tjniLibs.srcDirs \"" + p + "\"\n";
                    p = "src/main/social/" + SocialManager.DefinePlatform[info.social[i]] + "/res";
                    if (Directory.Exists(unityPath + "/" + p)) channelSourceSets += "\t\t\t\tres.srcDirs \"" + p + "\"\n";
                }
                channelSourceSets += "\t\t\t}\n";
                j++;
            }

            // if (j > 0)
            // {
            //   channelSourceSets += "\telse{\n";
            //   
            //   
            //   
            //   var adE = adList.Children.GetEnumerator();
            //   while (adE.MoveNext())
            //   {
            //     var one = adE.Current.AsObject;
            //     var name = one["name"];
            //     p = "src/main/ad/" + name + "/java";
            //     if (Directory.Exists(unityPath+"/"+p)) channelSourceSets += "\t\t\t\tjava.srcDirs \""+p+"\"\n";
            //     p = "src/main/ad/" + name + "/jniLibs";
            //     if (Directory.Exists(unityPath+"/"+p)) channelSourceSets += "\t\t\t\tjniLibs.srcDirs \""+p+"\"\n";
            //     p = "src/main/ad/" + name + "/res";
            //     if (Directory.Exists(unityPath+"/"+p)) channelSourceSets += "\t\t\t\tres.srcDirs \""+p+"\"\n";
            //   }
            //   adE.Dispose();
            //   var socialE = socialList.Children.GetEnumerator();
            //   while (socialE.MoveNext())
            //   {
            //     var one = socialE.Current.AsObject;
            //     var name = one["name"];
            //     p = "src/main/social/" + name + "/java";
            //     if (Directory.Exists(unityPath+"/"+p)) channelSourceSets += "\t\t\t\tjava.srcDirs \""+p+"\"\n";
            //     p = "src/main/social/" + name + "/jniLibs";
            //     if (Directory.Exists(unityPath+"/"+p)) channelSourceSets += "\t\t\t\tjniLibs.srcDirs \""+p+"\"\n";
            //     p = "src/main/social/" + name + "/res";
            //     if (Directory.Exists(unityPath+"/"+p)) channelSourceSets += "\t\t\t\tres.srcDirs \""+p+"\"\n";
            //   }
            //   socialE.Dispose();
            //   channelSourceSets += "\t}\n";
            // }
            e.Dispose();
            channelSourceSets += "\t\t}\n";
            channelSourceSets += "\t}\n";
            
            sign = "signingConfigs {\n";
            sign += "\t\trelease {\n";
            sign += "\t\t\tstoreFile file(\"../../android.keystore\")\n";
            sign += "\t\t\tstorePassword \"youlong\"\n";
            sign += "\t\t\tkeyAlias \"release\"\n";
            sign += "\t\t\tkeyPassword \"release\"\n";
            sign += "\t\t}\n";
            e = channels.channels.GetEnumerator();
            while (e.MoveNext())
            {
                var info = e.Current;
                if (info.target != BuildTarget.Android) continue;
                if (info.suffix == null || info.suffix == "") continue;
                sign += "\t\t" + info.suffix + " {\n";
                sign += "\t\t\tstoreFile file(\"../../android.keystore\")\n";
                sign += "\t\t\tstorePassword \"youlong\"\n";
                sign += "\t\t\tkeyAlias \"" + (!string.IsNullOrEmpty(info.keyAlias) ? info.keyAlias : info.suffix) + "\"\n";
                sign += "\t\t\tkeyPassword \"" + (!string.IsNullOrEmpty(info.keyPassword) ? info.keyPassword : info.suffix) + "\"\n";
                sign += "\t\t}\n";
            }
            e.Dispose();
            sign += "\t}\n";

            var channelMetaData = launcherXmlDoc.CreateElement("meta-data");
            channelMetaData.SetAttribute("name", ns.LookupNamespace("android"), "channel");
            channelMetaData.SetAttribute("value", ns.LookupNamespace("android"), "${channel}");
            launcherApplication.AppendChild(channelMetaData);
            var channelIdMetaData = launcherXmlDoc.CreateElement("meta-data");
            channelIdMetaData.SetAttribute("name", ns.LookupNamespace("android"), "channelId");
            channelIdMetaData.SetAttribute("value", ns.LookupNamespace("android"), "${channelId}");
            launcherApplication.AppendChild(channelIdMetaData);
            var channelPrivacyMetaData = launcherXmlDoc.CreateElement("meta-data");
            channelPrivacyMetaData.SetAttribute("name", ns.LookupNamespace("android"), "privacyDialog");
            channelPrivacyMetaData.SetAttribute("value", ns.LookupNamespace("android"), "${privacyDialog}");
            launcherApplication.AppendChild(channelPrivacyMetaData);
        }

        UpdateDefinesInFile(
          unityGradle,
          new Dictionary<string, string>(){
        {"*CHANNEL_FLAVORS*", channelFlavors},
        {"*CHANNEL_DEPENDENCIES*", channelDependencies},
        {"*CHANNEL_SOURCESETS*", channelSourceSets},
        {"*SIGN*", sign},
          }
        );

        UpdateDefinesInFile(
          launcherGradle,
          new Dictionary<string, string>(){
        {"*CHANNEL_FLAVORS*", channelFlavors},
        {"*CHANNEL_DEPENDENCIES*", channelDependencies},
        {"*CHANNEL_SOURCESETS*", channelSourceSets},
        {"*SIGN*", sign},
          }
        );
        {
            // mi
            AddPermission(xmlDoc, ns, "android.permission.INTERNET");
            AddPermission(xmlDoc, ns, "android.permission.ACCESS_WIFI_STATE");
            AddPermission(xmlDoc, ns, "android.permission.ACCESS_NETWORK_STATE");
            AddPermission(xmlDoc, ns, "android.permission.WRITE_EXTERNAL_STORAGE");
            AddPermission(xmlDoc, ns, "android.permission.READ_EXTERNAL_STORAGE");
            AddPermission(xmlDoc, ns, "android.permission.READ_PHONE_STATE");
            AddPermission(xmlDoc, ns, "android.permission.DOWNLOAD_WITHOUT_NOTIFICATION");
            AddPermission(xmlDoc, ns, "android.permission.REQUEST_INSTALL_PACKAGES");
        }
        {
            // taptap
            AddPermission(xmlDoc, ns, "android.permission.REQUEST_INSTALL_PACKAGES");
            AddQuery(xmlDoc, ns, "com.taptap");
        }
        //{
            // 跳过写入权限
        //    var metaData = xmlDoc.CreateElement("meta-data");
        //    metaData.SetAttribute("name", ns.LookupNamespace("android"), "unityplayer.SkipPermissionsDialog");
        //    metaData.SetAttribute("value", ns.LookupNamespace("android"), "true");
        //    application.AppendChild(metaData);
        //}

        // 保存
        xmlDoc.Save(xmlPath);
        launcherXmlDoc.Save(launcherXmlPath);

        // 添加接入口
        AppendDefinesInFile(
          unityPath + "/src/main/java/com/unity3d/player/UnityPlayerActivity.java",
          new Dictionary<string, string[]>(){
        {package+";",
          new string[]{"import com.ueffort.social.SocialSDK;",package+";\n\nimport com.ueffort.social.SocialSDK;"}},
        {
            "// Setup activity layout",
            new string[]{"protected void onActivityResult(int requestCode, int resultCode, Intent data) {", "\n    @Override\n" +
          "    protected void onActivityResult(int requestCode, int resultCode, Intent data) {\n" +
          "        SocialSDK.onActivityResult(requestCode, resultCode, data);\n" +
          "        super.onActivityResult(requestCode, resultCode, data);\n" +
          "}\n"}
          },
        {
            "setContentView(mUnityPlayer);",
          new string[]{"SocialSDK.onCreate(this);", "SocialSDK.onCreate(this);\n    setContentView(mUnityPlayer);"}},
        {
            "mUnityPlayer.destroy();",
            new string[]{"SocialSDK.onDestroy(this);", "SocialSDK.onDestroy(this);\n" +
            "        mUnityPlayer.destroy();"}},
        {
            "import android.app.Activity;",
            new string[]{"import com.ueffort.channel.ChannelSDK;", "import com.ueffort.channel.ChannelSDK;\nimport android.app.Activity;\nimport android.app.AlertDialog;\nimport android.content.DialogInterface;\nimport android.content.SharedPreferences;\n"}
        },
        {
            "getIntent().putExtra(\"unity\", cmdLine);",
            new string[]{"SharedPreferences base = getSharedPreferences(\"base\",MODE_PRIVATE);", "getIntent().putExtra(\"unity\", cmdLine);\nSharedPreferences base = getSharedPreferences(\"base\",MODE_PRIVATE);\n" +
                             "Boolean anInt = base.getBoolean(\"isFirstStart\",true);\n" +
                             "if (anInt==true && ChannelSDK.NeedPrivacyDialog(this)){\n" +
                             "AlertDialog.Builder dialog=new AlertDialog.Builder(UnityPlayerActivity.this);\n" +
                             "dialog.setTitle(\"隐私协议\");  //设置标题\n" +
                             "dialog.setMessage(\""+channels.privacy.Replace("\"", "\\\"")+"\");\n"+
                             "dialog.setCancelable(false);  //是否可以取消\n" +
                             "dialog.setNegativeButton(\"拒绝\", new DialogInterface.OnClickListener() {\n" +
                             "@Override\n" +
                             "public void onClick(DialogInterface dialogInterface, int i) {\n" +
                             "dialogInterface.dismiss();\n" +
                             "android.os.Process.killProcess(android.os.Process.myPid());\n" +
                             "}\n" +
                             "});\n" +
                             "dialog.setPositiveButton(\"同意\", new DialogInterface.OnClickListener() {\n" +
                             "@Override\n" +
                             "public void onClick(DialogInterface dialog, int which) {\n" +
                             "SharedPreferences.Editor editor = base.edit();\n" +
                             "editor.putBoolean(\"isFirstStart\",false);\n" +
                             "editor.commit();\n" +
                             "}\n" +
                             "});\n" +
                             "dialog.show();\n" +
                             "}\n"}
        }
        });
    }
    static XmlNode FindNode(XmlDocument xmlDoc, string xpath, string attributeName, XmlNamespaceManager ns, string attributeValue)
    {
        XmlNodeList nodes = xmlDoc.SelectNodes(xpath);
        for (int i = 0; i < nodes.Count; i++)
        {
            XmlNode node = nodes.Item(i);
            if (node.Attributes[attributeName, ns.LookupNamespace("android")] == null)
            {
                continue;
            }
            string _attributeValue = node.Attributes[attributeName, ns.LookupNamespace("android")].Value;
            if (_attributeValue == attributeValue)
            {
                return node;
            }
        }
        return null;
    }

    static void AddPermission(XmlDocument xmlDoc, XmlNamespaceManager ns, string permission)
    {
        var node = FindNode(xmlDoc, "manifest/uses-permission", "name", ns, permission);
        if (node == null)
        {
            XmlNode manifest = xmlDoc.SelectSingleNode("manifest");
            var ele = xmlDoc.CreateElement("uses-permission");
            ele.SetAttribute("name", ns.LookupNamespace("android"), permission);
            manifest.AppendChild(ele);
        }
    }

    static void AddQuery(XmlDocument xmlDoc, XmlNamespaceManager ns, string domain)
    {
        var node = FindNode(xmlDoc, "manifest/queries/package", "name", ns, domain);
        if (node == null)
        {
            XmlNode manifest = xmlDoc.SelectSingleNode("manifest/queries");
            if (manifest == null)
            {
                manifest = xmlDoc.SelectSingleNode("manifest");
                var queries = xmlDoc.CreateElement("queries");
                manifest.AppendChild(queries);
                manifest = queries;
            }
            var ele = xmlDoc.CreateElement("package");
            ele.SetAttribute("name", ns.LookupNamespace("android"), domain);
            manifest.AppendChild(ele);
        }
    }

    public static bool ContainText(string filePath, string text)
    {
        StreamReader streamReader = new StreamReader(filePath);
        string text_all = streamReader.ReadToEnd();
        streamReader.Close();

        int beginIndex = text_all.IndexOf(text);
        if (beginIndex == -1)
        {
            return false;
        }

        return true;
    }

    public static void WriteBelow(string filePath, string below, string text)
    {
        StreamReader streamReader = new StreamReader(filePath);
        string text_all = streamReader.ReadToEnd();
        streamReader.Close();

        int beginIndex = text_all.IndexOf(below);
        if (beginIndex == -1)
        {
            Debug.LogError(filePath + "中没有找到标致" + below);
            return;
        }

        int endIndex = text_all.LastIndexOf("\n", beginIndex + below.Length);

        text_all = text_all.Substring(0, endIndex) + "\n" + text + "\n" + text_all.Substring(endIndex);

        StreamWriter streamWriter = new StreamWriter(filePath);
        streamWriter.Write(text_all);
        streamWriter.Close();
    }

    public static string ReadAll(string filePath)
    {
        StreamReader streamReader = new StreamReader(filePath);
        string text_all = streamReader.ReadToEnd();
        streamReader.Close();
        return text_all;
    }

    public static string GenerateType(string path, JSONArray info, string type = null)
    {
        var typeString = "";
        var pluginString = "";
        var e = info.Children.GetEnumerator();
        while (e.MoveNext())
        {
            var one = e.Current.AsObject;
            var name = one["name"];

            var plugin = one["plugin"];
            var oneList = one["dependencies"].AsArray;
            if (oneList.IsNull) continue;
            var oneE = oneList.Children.GetEnumerator();

            if (type != null)
            {
                name = type + name;
                typeString += "\tdef " + name + "includes = []\n";
                typeString += "\tdef " + name + "libraries = []\n";
            }
            else
            {
                // 默认直接添加
                name = "";
            }
            while (oneE.MoveNext())
            {
                var s = oneE.Current.ToString();
                if (s.Contains("jar") || s.Contains("aar"))
                {
                    typeString += "\t" + name + "includes.add(" + s + ")\n";
                }
                else if (s.StartsWith("\"project"))
                {
                    typeString += "\t" + name + "libraries.add(" + s.Replace("\"", "") + ")\n";
                }
                else
                {
                    typeString += "\t" + name + "libraries.add(" + s + ")\n";
                    pluginString += "\timplementation " + s + "\n";
                }
            }
            oneE.Dispose();
            if (!plugin.IsNull && !string.IsNullOrWhiteSpace(plugin.Value))
            {
                typeString += "\t" + name + "libraries.add(project('" + plugin.Value + "'))\n";
                // 将依赖写入plugin中

                var gradle = path + "/" + plugin.Value + "/build.gradle";
                WriteBelow(gradle, "\n", "dependencies{\n" + pluginString + "}\n");
            }
        }
        e.Dispose();
        return typeString + "\n";
    }

    public static void GenerateSource(JSONArray info, string type, string unityPath)
    {
        var e = info.Children.GetEnumerator();
        while (e.MoveNext())
        {
            var one = e.Current.AsObject;
            var name = one["name"];

            var oneJavaList = one["java"].AsArray;
            if (!oneJavaList.IsNull)
            {
                var oneJavaE = oneJavaList.Children.GetEnumerator();

                while (oneJavaE.MoveNext())
                {
                    var s = oneJavaE.Current.ToString();
                    var source = unityPath + "/src/main/java/" + s.Replace("\"", "");
                    var dest = unityPath + "/src/main/" + type + "/" + name + "/java/" + s.Replace("\"", "");
                    FileTools.MoveFile(source, dest);
                }
                oneJavaE.Dispose();
            }

            var oneJniLibsList = one["jniLibs"].AsArray;
            if (!oneJniLibsList.IsNull)
            {
                var oneJniLibsE = oneJniLibsList.Children.GetEnumerator();

                while (oneJniLibsE.MoveNext())
                {
                    var s = oneJniLibsE.Current.ToString();
                    var source = unityPath + "/src/main/jniLibs/" + s.Replace("\"", "");
                    var dest = unityPath + "/src/main/" + type + "/" + name + "/jniLibs/" + s.Replace("\"", "");
                    FileTools.MoveFile(source, dest);
                }
                oneJniLibsE.Dispose();
            }

            var oneResList = one["res"].AsArray;
            if (!oneResList.IsNull)
            {
                var oneResE = oneResList.Children.GetEnumerator();

                while (oneResE.MoveNext())
                {
                    var s = oneResE.Current.ToString();
                    var source = unityPath + "/src/main/res/" + s.Replace("\"", "");
                    var dest = unityPath + "/src/main/" + type + "/" + name + "/res/" + s.Replace("\"", "");
                    FileTools.MoveFile(source, dest);
                }
                oneResE.Dispose();
            }
        }
        e.Dispose();
    }

}
